package com.xzj.mybatis.core;

import com.xzj.mybatis.annotation.Delete;
import com.xzj.mybatis.annotation.Insert;
import com.xzj.mybatis.annotation.Select;
import com.xzj.mybatis.annotation.Update;
import com.xzj.mybatis.utils.JdbcTemplate;
import com.xzj.mybatis.utils.MapperUtil;
import lombok.Builder;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ProjectName: SpringDemo
 * @Package: com.xzj.mybatis.core
 * @ClassName: DefaultSqlSession
 * @Author: xzj
 * @Description:
 * @Date: 2022/7/21 10:51
 * @Version: 1.0
 */
@Builder
public class DefaultSqlSession implements SqlSession{

    /**
     * 连接池
     */
    private final ArrayBlockingQueue<Connection> connectionPool;

    /**
     * 可以新建连接数量
     */
    private final AtomicInteger canConnection ;

    /**
     * 连接
     */
    private final JdbcTemplate jdbcTemplate;

    /**
     * 是否是临时连接
     */
    private final boolean isInterim;

    /**
     * @Author xzj
     * @Description 垃圾回收之前 把连接归还
     * @Date 14:58 2022/7/21
     * @param
     * @return
     **/
    @Override
    protected void finalize() throws Throwable {
        Connection connection = jdbcTemplate.getConnection();
        //如果是临时连接 用完关闭
        if(isInterim){
            connection.close();
            canConnection.incrementAndGet();
        }else{
            //如果不是，把线程放回队列中
            connectionPool.put(connection);
        }
        super.finalize();
    }

    @Override
    public <T> T selectOne(String statement) {
        return selectOne(statement,null);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        try {
            int i = statement.lastIndexOf(".");
            String serviceName = statement.substring(0, i);
            String methodName = statement.substring(i + 1);
            Class<T> clz = (Class<T>) Class.forName(serviceName);
            Method method = clz.getMethod(methodName);
            Select select = method.getAnnotation(Select.class);
            //获取参数集 key value
            Map<String, Object> objectMap = MapperUtil.mappingEntity(parameter.getClass(), parameter).get(0);
            //按顺序存放参数值
            ArrayList<Object> list = new ArrayList<>();
            String sql = MapperUtil.conversion(select.value(),list,objectMap);
            return jdbcTemplate.queryForObject(sql, clz,list.toArray());
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <E> List<E> selectList(String statement) {
        return selectList(statement,null);
    }

    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        try {
            int i = statement.lastIndexOf(".");
            String serviceName = statement.substring(0, i);
            String methodName = statement.substring(i + 1);
            Class<E> clz = (Class<E>) Class.forName(serviceName);
            Method method = clz.getMethod(methodName);
            Select select = method.getAnnotation(Select.class);
            //获取参数集 key value
            Map<String, Object> objectMap = MapperUtil.mappingEntity(parameter.getClass(), parameter).get(0);
            //按顺序存放参数值
            ArrayList<Object> list = new ArrayList<>();
            String sql = MapperUtil.conversion(select.value(),list,objectMap);
            return jdbcTemplate.queryForList(sql, clz,list.toArray());
        } catch (ClassNotFoundException | NoSuchMethodException e) {
           throw new RuntimeException(e);
        }
    }

    @Override
    public int insert(String statement) {
        return insert(statement,null);
    }

    /**
     * @Author xzj
     * @Description
     * @Date 16:31 2022/7/25
     * @param statement 类，方法名
     * @param parameter 插入对象 只能一个实体类 list map集合不考虑
     * @return
     **/
    @Override
    public int insert(String statement, Object parameter) {
        try {
            int indexOf = statement.lastIndexOf(".");
            String serviceName = statement.substring(0, indexOf);
            String methodName = statement.substring(indexOf + 1);
            Class<?> clz =  Class.forName(serviceName);
            Method method = clz.getMethod(methodName);
            Insert insert = method.getAnnotation(Insert.class);
            //获取参数集 key value
            Map<String, Object> objectMap = MapperUtil.mappingEntity(parameter.getClass(), parameter).get(0);
            //按顺序存放参数值
            List<Object[]> params = new ArrayList<>();
            String[] sqls = insert.value();

            for (int i = 0 ; i < sqls.length ; i++) {
                ArrayList<Object> list = new ArrayList<>();
                sqls[i] = MapperUtil.conversion(sqls[i],list,objectMap);
                params.add(list.toArray());
            }
            return jdbcTemplate.update(sqls,params);
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int update(String statement) {
        return update(statement,null);
    }

    @Override
    public int update(String statement, Object parameter) {
        try {
            int indexOf = statement.lastIndexOf(".");
            String serviceName = statement.substring(0, indexOf);
            String methodName = statement.substring(indexOf + 1);
            Class<?> clz =  Class.forName(serviceName);
            Method method = clz.getMethod(methodName);
            Update update = method.getAnnotation(Update.class);
            //获取参数集 key value
            Map<String, Object> objectMap = MapperUtil.mappingEntity(parameter.getClass(), parameter).get(0);
            //按顺序存放参数值
            List<Object[]> params = new ArrayList<>();
            String[] sqls = update.value();
            for (int i = 0 ; i < sqls.length ; i++) {
                ArrayList<Object> list = new ArrayList<>();
                sqls[i] = MapperUtil.conversion(sqls[i],list,objectMap);
                params.add(list.toArray());
            }
            return jdbcTemplate.update(sqls,params);
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int delete(String statement) {
        return delete(statement,null);
    }

    @Override
    public int delete(String statement, Object parameter) {
        try {
            int indexOf = statement.lastIndexOf(".");
            String serviceName = statement.substring(0, indexOf);
            String methodName = statement.substring(indexOf + 1);
            Class<?> clz =  Class.forName(serviceName);
            Method method = clz.getMethod(methodName);
            Delete update = method.getAnnotation(Delete.class);
            //获取参数集 key value
            Map<String, Object> objectMap = MapperUtil.mappingEntity(parameter.getClass(), parameter).get(0);
            //按顺序存放参数值
            List<Object[]> params = new ArrayList<>();
            String[] sqls = update.value();
            for (int i = 0 ; i < sqls.length ; i++) {
                ArrayList<Object> list = new ArrayList<>();
                sqls[i] = MapperUtil.conversion(sqls[i],list,objectMap);
                params.add(list.toArray());
            }
            return jdbcTemplate.update(sqls,params);
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void commit() {
        try {
            jdbcTemplate.getConnection().commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void commit(boolean force) {

    }

    @Override
    public void rollback() {
        try {
            jdbcTemplate.getConnection().rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void rollback(boolean force) {

    }

    @Override
    public void close() {
        try {
            jdbcTemplate.getConnection().close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void clearCache() {

    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{type},
                new MapperInvocationHandler(type,jdbcTemplate));
    }

    @Override
    public Connection getConnection() {
        return jdbcTemplate.getConnection();
    }
}
